﻿using ModelingProjectLib.Interfaces;
using ModelingProjectLib;
using System.Collections.ObjectModel;

namespace INSAwarsWPF
{
    //[Serializable()]
    /** ViewModel pour les Cases de la carte */
    public class CaseViewModel : ViewModelBase
    {
        /** Model encapsulé par le ViewModel */
        public Case CaseModel { get; set; }

        /** GameViewModel qui possède la CaseViewModel */
        public GameViewModel Conteneur { get; private set; }

        /** Tableau des couleurs utilisées pour les joueurs */
        public static string[] tabCouleur = { "Blue", "Red", "Yellow", "Green" };
        /** Tableau des couleurs réelles utilisées pour les joueurs */
        public static string[] tabCouleurCode = { "#275fd8", "#c71b10", "#e7e413", "#209400" };

        /** Construit une CaseViewModel possédée par _gvm à la position (row, col) qui encapsule la case _case */
        public CaseViewModel(GameViewModel _gvm, int _row, int _col, Case _case)
        {
            Row = _row;
            Column = _col;
            Unites = new ObservableCollection<UniteViewModel>();
            VilleCase = null;
            Conteneur = _gvm;

            CaseModel = _case;

            if (_case is DecorateurFer)
            {
                Ressource = "Fer";
                IsDecorated = true;
                TextureDeco = "/INSAwarsWPF;component/Images/Terrains/fer.png";
                Texture = getTextureString(((DecorateurFer)_case).CaseDecoree);
                Terrain = getTerrainString(((DecorateurFer)_case).CaseDecoree);
            }
            else if (_case is DecorateurFruit)
            {
                Ressource = "Fruit";
                IsDecorated = true;
                TextureDeco = "/INSAwarsWPF;component/Images/Terrains/fruit.png";
                Texture = getTextureString(((DecorateurFruit)_case).CaseDecoree);
                Terrain = getTerrainString(((DecorateurFruit)_case).CaseDecoree);
            }
            else
            {
                Ressource = "Pas de ressource";
                IsDecorated = false;
                TextureDeco = "";
                Texture = getTextureString(_case);
                Terrain = getTerrainString(_case);
            }
        }

        /** Fonction utilitaire : récupère la texture (en chaîne de caractère) correspondant au type de la case _case */
        private string getTextureString(Case _case)
        {
            if (_case is CaseDesert) return "/INSAwarsWPF;component/Images/Terrains/desert.png";
            else if (_case is CaseMontagne) return "/INSAwarsWPF;component/Images/Terrains/montagne.png";
            else if (_case is CasePlaine) return "/INSAwarsWPF;component/Images/Terrains/plaine.png";
            else return "";
        }

        /** Fonction utilitaire : récupère le type de la case _case sous forme de string */
        private string getTerrainString(Case _case)
        {
            if (_case is CaseDesert) return "Desert";
            else if (_case is CaseMontagne) return "Montagne";
            else if (_case is CasePlaine) return "Plaine";
            else return "";
        }

        /** Chaîne représentant le terrain de la case */
        public string Terrain { get; private set; }
        /** Chaîne représentant la ressource spéciale de la case */
        public string Ressource { get; private set; }

        /** Chemin vers la texture de terrain pour la case */
        public string Texture { get; private set; }
        /** Chemin vers la texture de décorateur pour la case */
        public string TextureDeco { get; private set; }

        /** Vrai si la case est décorée, faux sinon */
        public bool IsDecorated { get; set; }

        /** Position de la case */
        public int Row { get; private set; }
        public int Column { get; private set; }

        /** Description de la case, sous une forme compréhensible par le joueur */
        public string Description
        {
            get
            {
                return CaseModel.getDescription();
            }
        }

        /** Ville qui influence (contrôle) la case, null sinon */
        private VilleViewModel villeInfluente;
        public VilleViewModel VilleInfluente
        {
            get { return villeInfluente; }
            set
            {
                villeInfluente = value;
                RaisePropertyChanged("VilleInfluente");
                RaisePropertyChanged("IsSousInfluenceDeVille");
            }
        }

        /** Vrai si la case est sous l'influence d'une ville, faux sinon */
        public bool IsSousInfluenceDeVille
        {
            get { return VilleInfluente != null; }
        }

        /** Unités présentes sur la case */
        public ObservableCollection<UniteViewModel> Unites { get; set; }

        /** Ville présente sur la case, ou null sinon */
        private VilleViewModel villeCase;
        public VilleViewModel VilleCase
        {
            get { return villeCase; }
            set
            {
                villeCase = value;
                RaisePropertyChanged("VilleCase");
                RaisePropertyChanged("HasVille");
                //RaisePropertyChanged("IsVilleCreable");
                RaisePropertyChanged("HasUnite");
            }
        }

        /** Vrai ssi la case est sélectionnée */
        private bool isSelected;
        public bool IsSelected
        {
            get { return isSelected; }
            set { isSelected = value; RaisePropertyChanged("IsSelected"); }
        }

        /** Unité sélectionnée à l'intérieur de la case */
        private UniteViewModel selectedUnite;
        public UniteViewModel SelectedUnite
        {
            get { return selectedUnite; }

            set
            {
                if (selectedUnite != value)
                {
                    if (selectedUnite != null) selectedUnite.IsSelected = false;
                    selectedUnite = value;
                    if (selectedUnite != null) selectedUnite.IsSelected = true;
                    Conteneur.SelectedCase = this;
                    //Conteneur.View.focusOnSelectedUnite();
                    RaisePropertyChanged("SelectedUnite");
                    RaisePropertyChanged("HasUnite");
                    RaisePropertyChanged("HasUniteEnnemie");
                    //RaisePropertyChanged("IsVilleCreable");
                }
            }
        }

        /** Vrai ssi la case possède des unités */
        public bool HasUnite { get { return Unites.Count > 0; } } // avant : SelectedUnite != null

        /** Vrai ssi il y a une ville sur la case */
        public bool HasVille { get { return VilleCase != null; } }

        /** Vrai ssi il y a une unité ennemie sur la case */
        public bool HasUniteEnnemie
        {
            get
            {
                foreach (UniteViewModel uvm in Unites)
                    if (uvm.IsNotPossedeeParJoueurCourant) return true; // il y a un ennemi
                return false; // soit pas d'unite, soit pas d'ennemi
            }
        }

        /** Vrai ssi il y a une vilel ennemie sur la case */
        public bool HasVilleEnnemie { get { return HasVille && VilleCase.IsNotPossedeeParJoueurCourant; } }

        /** Vrai ssi il y a un directeur sur la case */
        public bool HasDirecteur
        {
            get
            {
                foreach (UniteViewModel ens in Unites)
                {
                    if (ens.UniteModel is Directeur)
                        return true;
                }
                return false;
            }
        }

        /** Ajoute la ville VilleViewModel à la case */
        public void ajouterVille(VilleViewModel villeViewModel)
        {
            VilleCase = villeViewModel;
            // on ajoute la ville au joueur courant
            Conteneur.Joueurs.JoueurCourant.Villes.Add(villeViewModel);
            //VilleCase.influencer(this);
            VilleCase.influencerZone(this);
        }


        /** Vrai ssi la case est pleine. Elle ne peut contenir que 4 joueurs. */
        public bool Pleine { get { return Unites.Count >= 4; } }


        /** Renvoie la case relative à la case courante avec un décalage de (rowDec, colDec)
         * ou null si la case est outofbounds
         */
        public CaseViewModel getCaseRelative(int rowDec, int colDec)
        {
            if ((Column + colDec) < 0 || (Column + colDec) > Conteneur.PartieCourante.CartePartie.Taille - 1
                || (Row + rowDec) < 0 || (Row + rowDec) > Conteneur.PartieCourante.CartePartie.Taille - 1)
                return null;
            else
                return Conteneur.Cases[(Column + colDec) + Conteneur.PartieCourante.CartePartie.Taille * (Row + rowDec)];
        }
    }
}
